import unittest
from pyson.gen import *
from argo.jdom import JdomParser
from java.io import StringReader
from java.util import ArrayList
import functools

class A(PysonObject):
    f1 = string()
    f2 = string()

class B(PysonObject):
    b1 = boolean()
    b2 = boolean()

class N(PysonObject):
    n1 = number()
    n2 = number()

class D(PysonObject):
    d1 = date()

class AR(PysonObject):
    ar1 = array(number)

class AR2(PysonObject):
    ar1 = array(array.elem(number))

class AR3(PysonObject):
    ar1 = array(array.elem(array.elem(string)))

class ARString(PysonObject):
    ar1 = array(string)

class StructAR(PysonObject):
    ar1 = array(struct)

class ST(PysonObject):
    st1 = struct()

class PreInit2(PysonObject):
    n1 = number(10)
    n2 = number(20)

class PreInit3(PysonObject):
    s1 = string("xyz")

class PreInit1(PysonObject):
    f1 = number(1)
    f2 = string(lambda: "abc")
    f3 = boolean(0)
    f4 = boolean(1)
    f5 = struct(PreInit2())
    f6 = struct(PreInit3)

class TestProperties(unittest.TestCase):
    def test_preinit(self):
        a = PreInit1()
        self.assertEquals("abc", a.f2)
        self.assertEquals("xyz", a.f6.s1)
        builder = a.createBuilder()
        output = compactFormat(builder)
        self.assertEquals(builder.build(), JdomParser().parse(StringReader(output)))

    def test_string(self):
        a = A()
        a.f1 = "abc"
        a.f2 = "XYZ"
        builder = a.createBuilder()
        output = compactFormat(builder)
        #self.assertEquals("{\"f1\":\"abc\",\"f2\":\"XYZ\"}", output)
        self.assertEquals(builder.build(), JdomParser().parse(StringReader(output)))

    def test_boolean(self):
        b = B()
        b.b1 = 1
        b.b2 = 0
        builder = b.createBuilder()
        output = compactFormat(builder)
        #self.assertEquals("{\"b1\":true,\"b2\":false}", output)
        self.assertEquals(builder.build(), JdomParser().parse(StringReader(output)))

    def test_number(self):
        n = N()
        n.n1 = 1
        n.n2 = 3.14159
        builder = n.createBuilder()
        output = compactFormat(builder)
        #self.assertEquals("{\"n1\":1,\"n2\":3.14159}", output)
        self.assertEquals(builder.build(), JdomParser().parse(StringReader(output)))

    def test_date(self):
        curDate = Date()
        curDateAsStr = dateFormat.format(curDate)

        d = D()
        d.d1 = curDate
        builder = d.createBuilder()
        output = compactFormat(builder)
        #self.assertEquals("{\"d1\":\"" + curDateAsStr + "\"}", output)
        self.assertEquals(builder.build(), JdomParser().parse(StringReader(output)))

    def test_array(self):
        ar = AR()
        ar.ar1 = (1, 2, 3)
        builder = ar.createBuilder()
        output = compactFormat(builder)
        #self.assertEquals("{\"ar1\":[1,2,3]}", output)
        self.assertEquals(builder.build(), JdomParser().parse(StringReader(output)))

    def test_array2(self):
        arrayBuilder = array.elem(number)((1, 2, 3))
        output = compactFormat(arrayBuilder)
        self.assertEquals("[1,2,3]", output)

        ar = AR2()
        ar.ar1 = ((1,), (2, 3), (4, 5, 6))
        builder = ar.createBuilder()
        output = compactFormat(builder)
        #self.assertEquals("{\"ar1\":[[1],[2,3],[4,5,6]]}", output)
        self.assertEquals(builder.build(), JdomParser().parse(StringReader(output)))

    def test_array3(self):
        ar = AR3()
        ar.ar1 = ((("a",), ("b", "c"), ("d", "e", "f")), (("A",), ("B", "C"), ("D", "E", "F")))
        builder = ar.createBuilder()
        output = compactFormat(builder)
#        self.assertEquals(
#                "{\"ar1\":[[[\"a\"],[\"b\",\"c\"],[\"d\",\"e\",\"f\"]],[[\"A\"],[\"B\",\"C\"],[\"D\",\"E\",\"F\"]]]}",
#                output)
        self.assertEquals(builder.build(), JdomParser().parse(StringReader(output)))

    def test_arrayFromJava(self):
        ar = ARString()
        javaList = ArrayList()
        javaList.add("AB")
        javaList.add("CD")
        javaList.add("EF")
        ar.ar1 = javaList
        builder = ar.createBuilder()
        output = compactFormat(builder)
        self.assertEquals("{\"ar1\":[\"AB\",\"CD\",\"EF\"]}", output)

    def test_struct(self):
        a = A()
        a.f1 = "ABC"
        a.f2 = "xyz"
        st = ST()
        st.st1 = a
        builder = st.createBuilder()
        output = compactFormat(builder)
        #self.assertEquals("{\"st1\":{\"f1\":\"ABC\",\"f2\":\"xyz\"}}", output)
        self.assertEquals(builder.build(), JdomParser().parse(StringReader(output)))

    def test_struct_array(self):
        a = A()
        a.f1 = "ABC"
        a.f2 = "xyz"

        b = B()
        b.b1 = 1
        b.b2 = 0

        star = StructAR()
        star.ar1 = (a, b)
        builder = star.createBuilder()
        output = compactFormat(builder)
        #self.assertEquals("{\"ar1\":[{\"f1\":\"ABC\",\"f2\":\"xyz\"},{\"b1\":true,\"b2\":false}]}", output)
        self.assertEquals(builder.build(), JdomParser().parse(StringReader(output)))

    def test_dynamic_struct(self):
        dynCls = PysonObjectMeta("DynCls", (PysonObject,), {
            "dyn1" : string("abc"),
            "dyn2" : number(1)
        })
        dynObj = dynCls()
        builder = dynObj.createBuilder()
        output = compactFormat(builder)
        self.assertEquals("{\"dyn1\":\"abc\",\"dyn2\":1}", output)

        st = ST()
        st.st1 = dynObj
        builder = st.createBuilder()
        output = compactFormat(builder)
        self.assertEquals("{\"st1\":{\"dyn1\":\"abc\",\"dyn2\":1}}", output)

def runTests():
    suite = unittest.TestLoader().loadTestsFromTestCase(TestProperties)
    unittest.TextTestRunner(verbosity=2).run(suite)
